/*
 * Copyright (c) jiucheng.org
 */
package org.jiucheng.template.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import org.jiucheng.template.Template;

/**
 * 
 * @author jiucheng jiucheng.org@gmail.com
 *
 */
public class Objs {
    
    @SuppressWarnings("rawtypes")
    public static Object get(Object obj, String attr) {
        if(attr == null) {
            return null;
        }
        if(attr.indexOf(":") > -1) {
            return getF(obj, attr);
        }
        if(obj == null) {
            return null;
        }
        if(obj instanceof Map) {
            return get1((Map) obj, attr);
        }
        if(obj instanceof List && "size".equals(attr)) {
            return ((List) obj).size();
        }
        return get2(obj, attr);
    }
    
    //sys:format($time, "YYYY-MM-dd HH:mm:ss")
    private static Object getF(Object obj, String attr) {
        int index = attr.indexOf(":");
        String alia = attr.substring(0, attr.indexOf(":"));
        Class<?> clazz = Template.getClass(alia);
        String methodName = attr.substring(index + 1, attr.indexOf("("));
        Method[] methods = clazz.getMethods();
        Method m = null;
        for(int i = methods.length - 1; i >= 0; i--) {
            m = methods[i];
            if(m.getName().equals(methodName)) {
                break;
            }
            m = null;
        }
        if(m != null) {
            attr = attr.substring(attr.indexOf("(") + 1, attr.lastIndexOf(")"));
            Object[] objs = null;
            if(attr.trim().length() != 0) {
                String[] attrs = attr.split(",");
                objs = new Object[attrs.length];
                for(int i = 0; i < attrs.length; i++) {
                    attr = attrs[i];
                    attr = attr.trim();
                    if("$".equals(attr)) {
                        objs[i] = obj;
                    }else if(attr.startsWith("$")) {
                        objs[i] = get(obj, attr.substring(1));
                    }else if(attr.startsWith("\"")) {
                        objs[i] = attr.substring(1, attr.length() - 1);
                    }else if("null".equalsIgnoreCase(attr)){
                        objs[i] = null;
                    }else if("true".equalsIgnoreCase(attr)) {
                        objs[i] = Boolean.TRUE;
                    }else if("false".equalsIgnoreCase(attr)) {
                        objs[i] = Boolean.FALSE;
                    }else {
                        objs[i] = Long.parseLong(attr);
                    }
                }
            }
            try {
                if(objs != null) {
                    return m.invoke(null, objs);
                }else {
                    return m.invoke(null);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    
    @SuppressWarnings("rawtypes")
    private static Object get1(Map map, String attr) {
        Object val = map.get(attr);
        if(val != null) {
            return val;
        }
        int len = attr.indexOf(".");
        if(len == -1) {
            len = attr.length();
        }
        String key = attr.substring(0, len);
        val = map.get(key);
        if(val == null || len >= attr.length()) {
            return null;
        }
        key = attr.substring(len + 1);
        if(key == null || "".equals(key)) {
            return val;
        }
        return get(val, key);
    }
    
    private static Object get2(Object obj, String attr) {
        int len = attr.indexOf(".");
        if(len == -1) {
            len = attr.length();
        }
        String key = attr.substring(0, len);
        key = key.substring(0, 1).toUpperCase() + key.substring(1);
        String methodName = "get" + key;
        Object val = null;
        try {
            Method m = obj.getClass().getMethod(methodName);
            val = m.invoke(obj);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        if(val == null || len >= attr.length()) {
            return val;
        }
        key = attr.substring(len + 1);
        if(key == null || "".equals(key)) {
            return val;
        }
        return get(val, key);
    }
}
